/*OutgoingMessageParser.java

other commands that might be worth implementing
/camp /logout /disconnect
/exit /quit
/rand /random /roll /rnd <min>? <max>
/dnd
/log /save
/time
/font
/cmdalias {alias} {command}
/cmdalias remove {alias}
/cmdalias clear
*/

package d20chat;

import java.util.regex.*;


/**
 * Takes a client side message and checks it, reformats it, and handles it if it's only client side or sends it on.
 * If Server is not yet started messsages go straight to IncomingMessageParser.
 */
public class OutgoingMessageParser 
{
    /**
     * the Client class being used, set in constructer.
     */
    private Client tempclient; 
    /**
     * the d20chatui class being used, set in constructer.
     */
    private d20chatui tempui; 
    /**
     * the D20Chat class being used, set in constructer.
     */
    private D20Chat theMain;
    
    /**
     * the message string as it is sent to the class.
     */
    private String unparsedMessage;
    /**
     * the message string as the class sends it out.
     */
    private String parsedMessage;
    
    /**
     * the name of the person who sent the message.
     */
    private String originName;
    /**
     * chat, command, or request.
     * chat is plain messages between people
     * commands come from the gm
     * requests effect what the program does and can come from anyone
     */
    private String type;

    /**
     * identifier for the type of message.
     */
    private String subType;
    /**
     * who the message is about.
     */
    private String targetName;
    /**
     * used for on off states for charactersheet and silence.
     */
    private String state;
    /**
     * the index of the end of the first word in the string.
     */
    private int endOfFirstWord;
    /**
     * the index of the end of the second word in the string.
     */
    private int endOfSecondWord;
    
    /**
     * for the text of messages, only part of message more than one word long.
     */
    private String text;
    /**
     * holds html formatting for the message.
     */
    private String format;
    
    /**
     * for keeping track of afk status.
     */
    private boolean away = false;
    

    /**
     * Checks for slash command, if no slash command appends /say all.
     */
    private void checkSay()
    {
        //does the message have a slash at it's start?
        boolean slashCommand = unparsedMessage.startsWith( "/" );
        
        //if the message does not contain a slash command then
        //it is a say to everyone, so append this information
        if( !slashCommand )
        {
            unparsedMessage = "/say all " + unparsedMessage;
        }
    }
    
    
    /**
     * Finds a math expression, evaluates it with StringMath, and adds the solution to the expression.
     * Math expressions are anything between [ and ].
     */
    private void doMath()
    {
        StringMath convert = new StringMath(); //object for evaluating math in strings
        String math = ""; //the expression to be evaluated
        String value; //the solution
        String newString =""; //temp string for creating the evaluated replacement
        int pos = 0; //position in the string for creating the evaluated replacement
        int length; //length of the string
        
        //make a pattern for finding the expression in square brackets
        Pattern mathPattern = Pattern.compile( "\\[.*?\\]" );
        //say that we'll be looking in the text string for the math expressions
        Matcher matcher = mathPattern.matcher( text );
        
        try
        {
            //while we're finding math experssions in the text string
            while(matcher.find())
            {
                //store the expression in math
                math = text.substring( matcher.start(), matcher.end() );

                //call StringMath.eval( expression ) and store the solution in value
                value = convert.eval(math);

                //make a new string adding the solution to the match expression
                //and to the evaluated string so far
                newString = newString + text.substring( pos, matcher.end()-1) + value + "]";
                
                //keep track of how much of the original string we've copied into our 
                //new string so far
                pos = matcher.end();
            }

            //store the length of the original text string
            length = text.length();


            if( pos >= text.length() )
            {  
                //the evaluated string (newString) is now the text
                text = newString;
            }
            else
            {
                //if some of the original string is still not copied over
                //add it to the newString and make this the text string now
                text = newString + text.substring( pos, length );
            }
        
            // Replace < and > with &lt; and &gt;
            text = text.replaceAll("\\<", "&lt;");
            text = text.replaceAll("\\>", "&gt;");
        }
        catch( ArithmeticException ae )
        {
            //some bad math happened so let the user know about it
            //in a system message and include the math expression that 
            //had the problem
            subType = "systemMessage";
            text = math + " " + ae.getMessage();
        
            // Replace < and > with &lt; and &gt;
            text = text.replaceAll("\\<", "&lt;");
            text = text.replaceAll("\\>", "&gt;");
        }
    }
    
    
    /**
     * Deconstructs message, calls methods to check message format, reconstructs message in correct form.
     * Checks a message for correct format, adds html, appends any info needed for server
     */
    private void formatContent()
    {
        boolean goodForm = false; //old variable, should be removed

        //removes anything that might be read as html the user entered
            //to prevent bad html from messing up other user's screens
        stripHTML(); 
        
        //inline css for displaying message with user's font choices
        //<!-- inline display info added in outgoing message -->
        //<span style = font-family: (families serperated by commas); font-size: (size); color: (color); background: (color);>
        //</span>
        format = 
            "<span style=\"" +
            "font-family:\'" + theMain.theSettings.chatFont + "\',sans-serif" + //defalults to sans-serif
            ";font-size:" + theMain.theSettings.chatSize + 
            ";color:rgb(" + theMain.theSettings.talkColor.red + "," + 
                theMain.theSettings.talkColor.green + "," + 
                theMain.theSettings.talkColor.blue + ")" +  
            ";\">";

        
        //junk initilizations, just so there is something there
        //also so later we can tell if the varaibles been set
        originName = "?"; //the name of the person who sent the message
        type = "?"; //chat, command, or request
        subType = "?"; //type of command or chat
        targetName = "?"; //who the message is about
        state = "?"; //used for ons and offs
        endOfFirstWord = 0;
        endOfSecondWord = 0;
        text = "?";
        
        //appended a space at the end for pattern matcher
        //because the matcher looks for characters followed by a space
        unparsedMessage = unparsedMessage + " ";
        
        //check to see if it needs to be turned into a say
        //(any message without a slash before it will become a say)
        checkSay();
        
        //strip the slash from the message
        stripSlash();
        
        //store the name of the sender        
        originName = theMain.theUser.getUsername();
        
        //stores a compiled regular expression that pulls out words
        Pattern wordPattern = Pattern.compile( ".*?\\s" );
        //object to connect our word expression to our message
        Matcher matcher = wordPattern.matcher( unparsedMessage );
        
        //find the first word in the message
        if( matcher.find() )
        {
            //this word will be the subtype such as tell or say for chat or silence for command
            subType = unparsedMessage.substring(matcher.start(), matcher.end()-1);
            
            //store the position after the first word, used for some text messages
            endOfFirstWord = matcher.end();  
        }
        
        //find the next word
        if( matcher.find() )
        {
            //this word will be the name of the person the message is about usually
            targetName = unparsedMessage.substring(matcher.start(), matcher.end()-1);
            
            //store the position after the second word, used for some text messages
            endOfSecondWord = matcher.end();
        }
        
        //save the rest of the message body
        text = unparsedMessage.substring( endOfSecondWord );
        
        //find the next word
        if( matcher.find() )
        {
            //this word will be a state message for some commands such as on or off for silence
            state = unparsedMessage.substring(matcher.start(), matcher.end()-1);
        }
        
        //call functions that check if the message is of a particular subType
        //and if it is formats it to that type
        //in if/else structure so that it will stop checking if it finds it's correct type
        if( subType.equalsIgnoreCase( "help" ) ||subType.equalsIgnoreCase( "h" ) )
        {
            //to indicate that it doesn't need to go on to the server
            type = "client";
            subType = "help";
             BareBonesBrowserLaunch.openURL("http://sourceforge.net/forum/forum.php?forum_id=622940");
        }
        else if ( systemMessage() )
        {
            //for the computer to send information and error
            //messages back to the user
        }
        else if( afk() )
        {
        }
        else if( say() )
        {
            /*
             messages starting with /say or it's equivalents
             these are chat messages meant for the whole room
             /say equivalents: /s, /amsg, /g, /c, /p
             */
        }
        else if( emote() )
        {
            /*
             messages starting with /emote or it's equivalents
             these are chat messages meant for the whole room.
             They are meant to represent actions.
             /emote equivalents /e, /em, /me 
             */
        }
        else if( tell() )
        {
            /*
             messages starting with /tell or it's equivalents
             these are chat messages meant for one person
             /tell equivalents: /t, /pm, /msg, /message, /whisper, /w, /send
             */
        }
        else if( hide())
        {
            /*
             messages starting with /hide or it's equivalents
             these are chat messages meant to go back to the user
             /hide equivalents: /echo and /hidden
             */
        }
        else if( silence() )
        {
       
        }
        else if( charactersheet() )
        {
            
        }
        else if( kick() )
        {

        }
        else if( makeGM() )
        {
            
        }
        else if( setPassword() )
        {
            
        }
        else if( changeName() )
        {
            
        }
        else if( userInfo() )
        {
            //message to send user information to the server
        }
        else if( hideProfile() )
        {
        }
        else if( password() )
        {        
            /*
            this is used by a user to submit a password
            to gain full admittance into a room
            The form when typed is /password <the password>.
             */
        }
        else if( profile() )
        {
        }
        else if( charNameChange() )
        {
        }
        else if( sendcharsheet() )
        {
        }
        else if( charsheet() )
        {
        }
        else if( clear() )
        {
        }
        else
        {
            //this is what we do with the message if it's nothing we recognize
            //it's basically a check message to sender so we classify it as chat
            type = "chat";
            //system messages are meant to be messages from the program to the user
            subType = "systemMessage";
            
            //let them know what message of theirs wasn't recognized so they can
            //redo it if they like
            text = "Unknown command : " + unparsedMessage;
        }
        
        //now that the message parts have been checked and filled in
        //put it all together and store it as a parsedMessage
        parsedMessage = originName + " " + type + " " + subType + " " + targetName + " " + text + " ";
    }
    
    
    /**
     * Checks if a message is for everyone in the room, and corrects the message components.
     * /say equivalents: /s, /amsg, /g, /c, /p
     * @return boolean true for a /say command, false otherwise
     */
    private boolean say()
    { 
         if( subType.equalsIgnoreCase("say") || 
                 subType.equalsIgnoreCase("s") ||
                 subType.equalsIgnoreCase("amsg") ||
                 subType.equalsIgnoreCase("g") ||
                 subType.equalsIgnoreCase("c") ||
                 subType.equalsIgnoreCase("p") 
            )
        {
             subType = "say";
             
            //this is a message from the user to another player so we're classifying it as chat
            type = "chat";
            
            if(targetName.equals("all") )
            {
                //if the user typed /say all then the body of the message starts at the end 
                //of the second word
                text = unparsedMessage.substring( endOfSecondWord );
            }
            else
            {
                //we're putting all as the target for this message which is true
                //but what is stored here doesn't actually mattter
                targetName = "all";
                //if the user didn't type all then the body starts at the end of the first word
                text = unparsedMessage.substring( endOfFirstWord );
            }
            
            //change math expressions in text to numbers
            doMath();
            
            //add inline css html to the message, so it will display with the user's font settings
            text = format + text + "</span>";
            
            //return true because this was a form of a say
            return true;
        }
         
         //return false because this wasn't a say type message if it got this far
         return false;
    }
    
    
    /**
     *    Checks if a message is for everyone in the room and represents an action, and corrects the message components.
     *    /emote equivalents: /e, /em, /me
     * @return boolean true for a /emote command, false otherwise
     */
    private boolean emote()
    { 
         if( subType.equalsIgnoreCase("emote") || 
                 subType.equalsIgnoreCase("e") ||
                 subType.equalsIgnoreCase("em") ||
                 subType.equalsIgnoreCase("me") 
            )
        {
             subType = "emote";
             
            //this is a message from the user to another player so we're classifying it as chat
            type = "chat";
            
            if(targetName.equals("all") )
            {
                //if the user typed /emote all then the body of the message starts at the end 
                //of the second word
                text = unparsedMessage.substring( endOfSecondWord );
            }
            else
            {
                //we're putting all as the target for this message which is true
                //but what is stored here doesn't actually mattter
                targetName = "all";
                //if the user didn't type all then the body starts at the end of the first word
                text = unparsedMessage.substring( endOfFirstWord );
            }
            
            //change math expressions in text to numbers
            doMath();
            
            //add inline css html to the message, so it will display with the user's font settings
            text = format + text + "</span>";
            
            //return true because this was a form of a say
            return true;
        }
         
         //return false because this wasn't a say type message if it got this far
         return false;
    }
    
    
    /**
     * Checks if a message is for one person, and corrects the message components.
     * /tell equivalents: /t, /pm, /msg, /message, /whisper, /w, /send
     * @return boolean true for a /tell command, false otherwise
     */
    private boolean tell()
    {
        if( subType.equalsIgnoreCase("tell") ||
                subType.equalsIgnoreCase( "t") ||
                subType.equalsIgnoreCase( "pm") ||
                subType.equalsIgnoreCase( "msg" ) ||
                subType.equalsIgnoreCase( "message" ) ||
                subType.equalsIgnoreCase( "whisper") ||
                subType.equalsIgnoreCase( "w") ||
                subType.equalsIgnoreCase( "send" )
           )
        {
            subType = "tell";
            //this is a message from the user to another player so we're classifying it as chat
            type = "chat";
            //change math expressions to numbers
            doMath();

            //the text consitsts of the the message they sent and their text formatting in css form
            text = format + text + "</span>";
            
            //it's a type of /tell so return true
            return true;
        }
        
        //if we're here it's not a type of /tell so return false
        return false;
    }

      

    /**
     * Checks if a message is visible only to the sender, and corrects the message components.
     * Description: for sending messages to the user's self
     * Mostly useful for rolling dice.
     * /hide equivalents: /echo and /hidden
     * @return boolean true for a /hide command, false otherwise
     */
    private boolean hide()
    {
         if( subType.equalsIgnoreCase("hide") ||
                 subType.equalsIgnoreCase("echo") ||
                 subType.equals( "hidden" )
            )
        {
            subType = "hide";
            //since their is no target name the message starts earlier
            text = unparsedMessage.substring( endOfFirstWord );
            
            doMath();
            
            //it's just a chat message, and does not change the program
            //so type  is chat
            type = "chat";
            
            //a hidden message is basically a tell to the sender
            //though it doesn't really matter what you say here
            targetName = "you";
            
            //add the html to the text
            text = format + text + "</span>";
            
            //it's a type of hidden message so it's true
            return true;
        }
         
        //if we got this far it's not a hidden message so false 
        return false;
    }


    /**
     * Checks for a message meant to inform user of the state of the system, and corrects the message compontents.
     * @return boolean true for a /systemMessage command, false otherwise
     */
    private boolean systemMessage()
    {
        if( subType.equalsIgnoreCase("systemMessage" ) )
        {
            subType = "systemMessage";
            
            //it's a message that doesn't effect the system so it's chat
            type = "chat";

            //it goes back to the user so will just set the target name to you
            //but this doesn't really need to be anything particular
            targetName = "you";
            
            //what we want to tell the user will be after the first word
            text = unparsedMessage.substring( endOfFirstWord );
            
            //the message is a system message so return true
            return true;
        }
        else
        {
            //if we've got here it's not a system message so return false
            return false;
        }
    }
    
    
    /**
     * Checks if a message is to allow or disallow the players to speak, and corrects the message compontents.
     * @return boolean true for a /silence command, false otherwise
     */
    private boolean silence()
    {
        if(subType.equalsIgnoreCase("silence") )
        {
            subType = "silence";
            
            //this is a message a gm would send so we're classifying it as a command
            type = "command";
            
            if( targetName.equalsIgnoreCase("on") )
            {
                //if user entered on without a targetName
                
                //if no name was entered after the silence command
                //then it was meant for everyone
                targetName = "all";
                
                //on was entered, so we're turning silence on
                text = "on";
            }
            else if( targetName.equalsIgnoreCase("off") )
            {
                //if user entered on without a targetName

                //if no name was entered after the silence command
                //then it was meant for everyone
                targetName = "all";
                
                //off was entered so we're turning silence off
                text = "off";
            }
            else if( state.equalsIgnoreCase( "on" ) || state.equalsIgnoreCase( "off" ) )
            {
                //targetName will already hold the name of the person to silence
                
                //when we put the final message together we're expecting text
                //not state, so store the sate in text
                text = state;
            }
            else if( targetName.equals("?") )
            { 
                // /silence was entered by istelf
                //this is the same as /silence all on
                targetName = "all";
                text = "on";
            }
            else
            {
                //user entered a name, but no state

                //we assume user meant on
                text = "on";  
            }
            
            //it was a /silence command so return true
            return true;
        }
        else if( subType.equalsIgnoreCase( "unsilence" ) )
        {   
            //not a /silence but an /unsilence
            //it comes from the gm so it's a command
            type = "command";
            subType = "silence";
            text = "off"; 
             //if a name was given it's already in the right place
            
             if( targetName.equals("?") )
             {
                //no name was given so assume everyone is allowed to talk
                targetName = "all";
             }

             //the messsage is a type of silence command so return true
             return true;
        }
        //the message was not a type of silence command if we reached here
        //so return false
        return false;
    }
    
    
    /**
     * Checks if the message is a command to make another player the GM, and corrects the message components.
     * /makeGM equivalents: /make_gm, /makeLeader, /make_leader, /promote, /pr
     * @return boolean true for a /makeGM command, false otherwise
     */
    private boolean makeGM()
    {
        if( subType.equalsIgnoreCase( "makeGM" ) || 
                subType.equalsIgnoreCase( "make_gm" ) || 
                subType.equalsIgnoreCase( "makeLeader" )|| 
                subType.equalsIgnoreCase( "make_leader" ) ||
                subType.equalsIgnoreCase( "promote" ) ||
                subType.equalsIgnoreCase( "pr" ) 
           )
        {
            subType = "makeGM";
            
            if( targetName.equals("?") )
            {
                //no name was given so error message
                type = "chat";
                subType = "systemMessage";
                text = "No name was entered in the makeGM command.";
            }
            else
            {
                //this is a message a gm would send so we're classifying it as a command
                type = "command";
                //name is already in the right variable
                //text doesn't matter so we just put something there
                text = "blah";
            }
            
            //it's a makegm command so return true
            return true;
        }
        
        //if we got this far it's not a make gm command so return false
        return false;
    }
    
    
    /**
     * Checks if it's a message to remove unwanted players from room, and corrects the message components.
     * /kick equivalents: /uninvite, /u, /un
     * @return boolean true for a /kick command, false otherwise
     */ 
    private boolean kick()
    {
        if( subType.equalsIgnoreCase( "kick" ) ||
                subType.equalsIgnoreCase( "univite" ) ||
                subType.equalsIgnoreCase( "u" ) ||
                subType.equalsIgnoreCase( "un" )
           )
        {
            subType = "kick";
            
            if( targetName.equals("?") )
            {
                //no name was entered so error message
                type = "chat";
                subType = "systemMessage";
                text = "No name was entered in the kick command.";
            }
            else
            {
                //this is a message a gm would send so we're classifying it as a command
                type = "command";
                
                //name is already filled in targetName
                
                //no text needed, so just putting something in the spot
                text = "now";
            }
            
            //it was a /kick message so return true
            return true;
        }
        
        //it wasn't a /kick message so return false
        return false;
    }
    
    
    /**
     * Checks if it's a message to give the server a new password, and corrects the message components.
     * @return boolean true for a /setPassword command, false otherwise
     */
    private boolean setPassword()
    {
        if( subType.equalsIgnoreCase("setPassword") )
        {
                //this is a message a gm would send so we're classifying it as a command
                type = "command";
                subType = "setPassword";
                
                
            if( targetName.equals("?") )
            {
                //no second word means no password, so assume they don't want a password anymore
                //we'll use none as the key word to indicate this
                text = "none";
                theMain.serverPassword = null;
            }
            else
            {
                //the second word they typed (stored as targetName) becomes 
                //the text of the message
                text = targetName;
                theMain.serverPassword = text;
            }
            
            //the message was for setting the password so return true
            return true;
        }
        
        //if were here it's not this kind of message so return false
        return false;
    }
    
    
    /**
     * Checks if it's a message to submit a password to the Server for admitance to the room, and corrects the message components.
     * The form when typed is /password <the password>.
     * @return boolean true for a /password command, false otherwise
     */
    private boolean password()
    {
        if( subType.equalsIgnoreCase("password") )
        {
            subType = "password";
            /*
             type is request because it can come from a regular player
             and effects the state of the room
             */
            type = "request"; 
            /*
             The password was the second word in the message  so it's held 
             in targetName the password belongs in the text part of 
             the reformatted message
             */
            text = targetName; 
            
            //the message was for setting the password so return true
            return true;
        }
        
        //if were here it's not this kind of message so return false
        return false;
    }
    
    /**
     * Checks if it's a message for making sheets viewable or not, and corrects message components.
     * @return boolean true for a /charactersheet command, false otherwise
     */
    private boolean charactersheet()
    {
        if( subType.equalsIgnoreCase( "charactersheet" ) )
        {
            subType = "charactersheet";
            //this is a message a gm would send so we're classifying it as a command
            type = "command";
            
            //doesn't matter what you put here
            //
            
            if( targetName.equals("on") || state.equals("on") )
            {
                //user entered on, so we're turning viewing on
                text = "on";
                targetName = "all";
            }
            else if( targetName.equalsIgnoreCase("off") || state.equalsIgnoreCase("off") )
            {
                //user entered off, so we're turning viewing off
                text = "off";
                targetName = "all";
            }
            else
            {
                //the user didn't indicate wheather the charactersheets were supposed to be
                //turned on or off error message
                type = "chat";
                subType = "systemMessage";
                text = "To turn on/off character sheets enter : /charactersheet on OR /charactersheet off.";
            }
            //this is a message to turn charctersheets on or off so return true
            return true;
        }
        //this is not a message about character sheet state if we got here
        //so return false
        return false;
    }
    
    
    
    /**
     * Checks if it's a message that sends the username and profile on to the server, and corrects message components.
     * @return boolean true for a /userInfo command, false otherwise
     */
    private boolean userInfo()
    {
        if( subType.equals( "userInfo" ) )
        {
             /*
             type is request because it can come from a regular player
             and effects the state of the room
             */
            type = "request";
            //just to have something in the targetName spot
            targetName = "blah";
            
            //after userInfo would be a string created by the User class
            //that contains the user's username and profile
            text = unparsedMessage.substring( endOfFirstWord );
            
            //it was a userInfo message so return true
            return true;
        }
        
        //it wasn't a userinfo message if we got here so return false
        return false;
    }
    
    /**
     * Checks if it's a request message from a user to see another user's profile, and corrects message contents.
     * /profile equivalents: /inspect, /ins, /who, and /whois
     * @return boolean true for a /profile command, false otherwise
     */
    private boolean profile()
    {
        if( subType.equalsIgnoreCase( "profile" ) ||
            subType.equalsIgnoreCase( "inspect" ) ||
            subType.equalsIgnoreCase( "ins" ) ||
            subType.equalsIgnoreCase( "who" ) ||
            subType.equalsIgnoreCase( "whois" )
            )
        {
            subType = "profile";
            //something sent from a user that effects others so it's a request
            type = "request";
            //just so there is some text
            text = "please";
            //it is a profile request, return true
            return true;
        }
        //it is not a profile request, return false
        return false;
    }
    
    /**
     * Checks if it's a message to the Server saying that the profile shouldn't be shared, and corrects message components.
     * @return boolean true for a /hideProfile command, false otherwise
     */
    private boolean hideProfile()
    {
        if( subType.equals( "hideProfile" ) )
        {
            type = "request";
            //the rest doesn't matter
            return true;
        }
        else
        {
            return false;
        }
    }
    
    
    /**
     * Checks if it's a message to change the user's characater name.
     * @return boolean true for a /charNameChange command, false otherwise
     */
    private boolean charNameChange()
    {      
        if( subType.equalsIgnoreCase("charNameChange") )
        {
            if( targetName.equals("?") )
            {
                //error message because there is no new name
                type = "chat";
                subType = "systemMessage";
                text = "No name was entered in the charNameChange command.";
            }
            else
            {
                subType = "charNameChange";
                //not a gm command, not chat, so request
                type = "request";
                //just to have soemthing here
                targetName = originName;
                //padded with special characters so it's easy to catch all of a
                //multi word name
                theMain.theUser.setCharacterName(unparsedMessage.substring( endOfFirstWord ));
                text = "\u8594" + unparsedMessage.substring( endOfFirstWord ) + "\u8594";
            }
            //is a character name change so return true
            return true;
        }
        //it's not a character name change so return false
        return false;
    }
    
    /**
     * If it's a afk message, toggles the user's charactername to or from displaying afk.
     * Reformatted to look like a charNameChange message.
     * /afk equivalent: /away
     * @return boolean true for a /afk command, false otherwise
     */
    private boolean afk()
    {      
        if( subType.equalsIgnoreCase("afk") ||
                subType.equalsIgnoreCase("away")
                )
        {
                subType = "charNameChange";
                //not a gm command, not chat, so request
                type = "request";
                //just to have soemthing here
                targetName = originName;
                //padded with special characters so it's easy to catch all of a
                //multi word name
                
            if( away == false )
            {
                away = true;
                text = "\u8594" + theMain.theUser.getCharacterName() + " - afk\u8594";
            }
            else
            {
                away = false;
                text = "\u8594" + theMain.theUser.getCharacterName() + "\u8594";
            }
            //is an afk so return true
            return true;
        }
        //it's not an afk so return false
        return false;
    }
    
    
    /**
     * Checks if it's a message to change the user name of a player, changes the username, and corrects message contents.
     * /changeName equivalents: /name and /nick
     * @return boolean true for a /changeName command, false otherwise
     */
     private boolean changeName()
    {
        if( subType.equalsIgnoreCase("changeName") ||
                subType.equalsIgnoreCase("name") ||
                subType.equalsIgnoreCase("nick")
           )
        {
            if( targetName.equals("?") )
            {
                //there is no new name entered so error message
                type = "chat";
                subType = "systemMessage";
                text = "No name was entered in the changeName command.";
            }
            else
            {
                subType = "changeName";
                //the old name will already be in originName
                //and the new name is alrady in targetName
                type = "request";
                //what is entered here doesn't matter
                text = "blah";
                
                //we want to change the name client side too
                //so set the variable using the main class
                theMain.theUser.setUsername(targetName);
                //when a name is set it's stripped of bad characters
                //so use the name after it's set, not before
                targetName = theMain.theUser.getUsername();
            }
            //it was a user name change message so return true
            return true;
        }
        //it was not a user name change message so return false
        return false;
    }
       
     
    /**
     * Checks if it's a message to send a charactersheet to another player, and corrects message contents.
     * @return boolean true for a /sendcharsheet command, false otherwise
     */
    private boolean sendcharsheet() 
    {
        if(subType.equalsIgnoreCase("sendcharsheet"))
        {
            if( targetName.equals("?") )
            {
                //no name was entered for who the sheet was to go to so error message
                type = "chat";
                subType = "systemMessage";
                text = "No name was entered in the sendcharsheet command.";
            }
            else
            {
                //anyone could send this message and it has an effect so it's a request
                type = "request";
                //the charactersheet will be all the message after /sendcharsheet and the name
                text = unparsedMessage.substring( endOfSecondWord );
                subType = "sendcharsheet";
            }
            //the user is sending a character sheet so return true
            return true;
        }
        else
        {
            //the user isn't sending a character sheet so return false
            return false;
        }
    }
    
    
    /**
     * Checks if it's a command to clear the chat buffer, and if so clears the chat buffer.
     * This message sets type to client so it doesn't send a message to the Server.
     * @return boolean true for a /clear command, false otherwise
     */
    private boolean clear() 
    {
        if(subType.equalsIgnoreCase("clear") ||
                subType.equalsIgnoreCase( "cls" )
        )
        {
            type = "client";
            theMain.gui.buffer.clearbuffer();
            tempui.tempchatwindowoutput( "" );
            return true;
        }
        else
        {
            return false;
        }
    }

    
    /**
     * Checks if it's a request from a player to see anther player's charactersheet, and corrects message contents.
     * @return boolean true for a /charsheet command, false otherwise
     */
    private boolean charsheet() 
    {
        if(subType.equalsIgnoreCase("charsheet"))
        {
            if( targetName.equals("?") )
            {
                //error message
                type = "chat";
                subType = "systemMessage";
                text = "No name was entered in the charsheet command.";
            }
            else
            {
                //from user and effects program so it's a request
                type = "request";
                //doesn't matter what this says
                text = "blah";
                subType = "charsheet";
            }
            return true;
        }
        else
        {
            return false;
        }
    }
       
    
    /**
     * Strips any text between < and > out of the message to remove html.
     */
    private void stripHTML()
    {
        unparsedMessage = unparsedMessage.replaceAll("\\<.*?\\>","");
    }
    
    
    /**
     * Removes the slash in front of the slash command in a message.
     */
    private void stripSlash()
    {
        int pos; //where the slash is in the string
        StringBuffer buffer; //an object to manipulate the string
        
        //find the slash
        pos = unparsedMessage.indexOf('/');
        //store a copy of the message in the buffer
        buffer = new StringBuffer( unparsedMessage );
        //delete the / character
        buffer.deleteCharAt(pos);
        //put the corrected string back into unparsedMessage
        unparsedMessage = buffer.toString();
    }
 

    /**
     * Handles a message from the client either performing some operation or passing the formatted message on.
     * @param message A String representing anything that the user or the machine wants to tell the Server or Client.
     */
    public void sendMessage( String message ) 
    {
        //store the message entered into the ui
        unparsedMessage = message;
        
        if( !unparsedMessage.isEmpty() )
        {
            //check the string and construct the message
            formatContent();
            
            //check if the client is connected to a server
            if( type.equals( "client" ) )
            {
                //do nothing, it's already being done
            }
            else if( theMain.connected == true )
            {
                //send the message to the client class to pass to the server
                tempclient.SendMessage( parsedMessage ); 
            }
            else if( (type.equals("chat") && !subType.equals("tell")) )
            {
                //if not connected they can still send say and /hide
                //as well as recieve system messages
                //on their own screen
                //pass directly to incoming message parser
                theMain.InParse.CheckType( parsedMessage );
            }
            else
            {
                //if it's a command that needs a server
                //let them know they don't have one
                tempui.tempchatwindowoutput( "You are not connected to a server." );
            }
        }      
    }


    /**
     * Constructor, recieves other classes so they can be referred to.
     * @param gui The user interface.
     * @param clientthread the thread that sends messages to the server
     * @param thisD20Chat the main class
     */
    public OutgoingMessageParser( d20chatui gui, Client clientthread, D20Chat thisD20Chat ) 
    {
        tempclient = clientthread;
        tempui = gui;
        theMain = thisD20Chat;
    }
}
